package cbs.jdtag;

import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DataModel2 extends Observable {
	
	private static transient final Logger LOGGER = Logger.getLogger(MainApp.class.getName());
	
	public class Token implements Comparable {
		public Integer id;
		public Integer pos;
		public Integer lineNumber;
		public String key;
		public String text;
		public List<Alignment> alignments = new ArrayList<Alignment>(); 
		
		// visual stuff
		public int x;
		public int y;
		public boolean highlighted;
		public TokenLabel2 tokenLabel;

		public int compareTo(Object o) {
			Token t = (Token) o;
			if (id.intValue() < t.id.intValue()) {
				return -1;
			}
			else if (id.intValue() > t.id.intValue()) {
				return 1;
			}
			else {
				return 0;	
			}
		}
	}
	
	public class Alignment extends Observable {
		private List<Token> srcTokens = new ArrayList<Token>();
		private List<Token> tgtTokens = new ArrayList<Token>();
		private String type = "";
		private String creator = "";
		
		public List<Token> getSrcTokens() {
			return srcTokens;
		}
		public void addSrcToken(Token srcToken) {
			srcTokens.add(srcToken);
			Collections.sort(srcTokens);
		}
		public List<Token> getTgtTokens() {
			return tgtTokens;
		}
		public void addTgtToken(Token tgtToken) {
			tgtTokens.add(tgtToken);
			Collections.sort(tgtTokens);
		}
		
		@Override
		public boolean equals(Object o) {
			Alignment a = (Alignment) o;
			if (srcTokens.size() != a.srcTokens.size()) {
				return false;
			}
			
			if (tgtTokens.size() != a.tgtTokens.size()) {
				return false;
			}
			
			boolean equal = true;
			
			for (int i = 0; i < srcTokens.size(); ++i) {
				Token s = srcTokens.get(i);
				Token sa = a.srcTokens.get(i);
				
				if (s.id != sa.id) {
					equal = false;
				}
			}
			for (int i = 0; i < tgtTokens.size(); ++i) {
				Token s = tgtTokens.get(i);
				Token sa = a.tgtTokens.get(i);
				
				if (s.id != sa.id) {
					equal = false;
				}
			}
			
			return equal;
		}
		public String getType() {
			return type;
		}
		public void setType(String type) {
			this.type = type;
		}
		public String getCreator() {
			return creator;
		}
		public void setCreator(String creator) {
			this.creator = creator;
		}
	}
	
	public class TokenFile {
		public String key;
		public File href;
		public String sign;
	}
	
	private File alignmentFile;
	public Map<String, TokenFile> tokenFiles = new HashMap<String, TokenFile>();
	private String encoding;
	public boolean saved;
	private HashMap<String, LinkedHashMap<Integer, Token>> sidesById = new HashMap<String, LinkedHashMap<Integer,Token>>(); // string=key, integer=id
	private HashMap<String, LinkedHashMap<Integer, Token>> sidesByPos = new HashMap<String, LinkedHashMap<Integer,Token>>(); // string=key, integer=pos
	private List<String> keys = new ArrayList<String>();
	private List<Alignment> alignments = new ArrayList<Alignment>();
	
	public void reset() {
		setAlignmentFile(null);
		tokenFiles.clear();
		saved = true;
		sidesById.clear();
		sidesByPos.clear();
		keys.clear();
		alignments.clear();
	}
	
	public Token getTokenById(String key, Integer id) {
		return sidesById.get(key).get(id);
	}
	
	public void addSideById(String key, LinkedHashMap<Integer, Token> tokens) {
		sidesById.put(key, tokens);
		setChanged();
		notifyObservers();
	}
	
	public void addSideByPos(String key, LinkedHashMap<Integer, Token> tokens) {
		sidesByPos.put(key, tokens);
	}
	
	public Token getTokenByPos(String key, Integer pos) {
		return sidesByPos.get(key).get(pos);
	}
	
	public boolean isEmpty() {
		return sidesById.isEmpty();
	}
	
	public Iterator<Token> getTokenIterator(String key) {
		return sidesById.get(key).values().iterator();
	}
	
	public void addKey(String key) {
		keys.add(key);
	}
	
	public String getKey(int index) {
		return keys.get(index);
	}
	
	public Integer getKeyCount() {
		return keys.size();
	}
	
	public Integer getMaxTokenCount() {
		int max = -1;
		Iterator<String> it = keys.iterator();
		while (it.hasNext()) {
			String key = it.next();
			if (sidesById.get(key).size() > max) {
				max = sidesById.get(key).size();
			}
		}
		return max;
	}
	
	public boolean alignmentContains(Alignment a) {
		if (alignments.contains(a)) {
			return true;
		}
		else {
			
			return false;
		}
	}
	
	public void alignmentRemove(Alignment a) {
		
		Iterator<Token> it;
		it = a.srcTokens.iterator();
		while (it.hasNext()) {
			Token t = it.next();
			t.alignments.remove(a);
		}
		it = a.tgtTokens.iterator();
		while (it.hasNext()) {
			Token t = it.next();
			t.alignments.remove(a);
		}
		alignments.remove(a);
		a = null;
		setChanged();
		notifyObservers();
	}
	
	public void alignmentAdd(Alignment a) {
		alignments.add(a);
		setChanged();
		notifyObservers();
	}

	public void setAlignments(List<Alignment> alignments) {
		this.alignments = alignments;
		setChanged();
		notifyObservers();
	}
	
	public Iterator<Alignment> getAlignmentIterator() {
		return alignments.iterator();
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	public String getEncoding() {
		return encoding;
	}

	public File getAlignmentFile() {
		return alignmentFile;
	}

	public void setAlignmentFile(File alignmentFile) {
		this.alignmentFile = alignmentFile;
		LOGGER.log(Level.INFO, "Alignment file is now set to \"{0}\".", alignmentFile);
	}
}
